/* 分析
1 当前页面的数据来源 三个来源
  1 当前地位 来自于 redux
  2 热门城市 接口
  3 所有城市 接口 
2 如何处理数据格式
  1 先排序
  2 再去设想 这个数组该如何构造 才能够方便的进行循环 
3 拿到当前城市
  1 却发现 直接打开城市列表页面(直接刷新打开 不经过首页) 获取不到 当前城市
    1 原因: 把获取当前城市的代码 写在了 首页的组件中 
  2 解决
    1 有很多页面可以不经过首页就打开
    2 把获取当前地理位置的代码 写在 根组件 App.js 
      不管是哪个页面 都会经过根组件的渲染处理 
    3 修改 citySearch 里面的代码 


5 长列表的渲染模式  重要!! 
  1 假如后台有10万条数据  前端如何渲染 性能才比较好 
    1 整页加载
      1 浪费性能 前端和后端都浪费  
    2 分页加载  
      1 第一次加载的时候 拿 50条回来
        1 页面就拿50条数组 渲染
        ....
        每一次去新的加载的时候 都拿50条
        页面马上跟渲染 新的50条
        ....
        list 的数组长度 = 10万
        页面中的dom元素的数量 也是 10万 
    3 可视区域渲染
      1 最终的效果
        list 数组的长度 = 10万
        页面中的dom元素的数量  只有 50个 (永远都是用户想要看到的50条数据)
        1-50 
        51-100
        101-150

6 字母列表
  1 构造数据 将它循环显示出来 
  2 点击右侧字母 页面滑动
  3 滑动页面 右侧字母切换
 */

import React, { Component } from "react"

// 1.在该组件中获取 当前定位城市--从react-redux中获取
// 1.1 引入 react-redux中connect 目的：连接 组件和store的对象 
import { connect } from 'react-redux'
// 引入 仓库中的 获取 当前定位城市方法
// import { getCityNameCreate } from '../../store/actionCreator'

// 引入封装的axios 请求
import { request } from '../../utils/request'
// 引入antui中的组件
import { NavBar, Icon } from 'antd-mobile';

import indexCss from './indexCss.module.scss'
// 引入长列表渲染 插件
import { List } from 'react-virtualized'
//  引入 仓库中的 获取 修改定位城市方法
import { changeCityName } from '../../store/actionCreator'


class Index extends Component {

    // 定义数据
    state = {
        selectList: [],    //最终可以渲染到页面的数组 
        letterList: [],    //字母数组
        currentIndex: 0    //选中字母的索引
    }
    //优化 滑动页面 右侧字母切换 业务 --定义ref操作dom 
    constructor() {
        super();
        this.listRef = React.createRef();
    }
    // 渲染城市列表业务
    async componentDidMount() {
        // 1.当前定位城市数据
        // console.log(this.props.cityName);
        const { cityName } = this.props;
        // 2.获取热门城市数据
        // request.get('/area/hot');
        // 3.获取所有城市数据
        // request.get('/area/city?level=1');

        //4.将数据 合并和处理 成  我们要展示的数据（  方便我们 循环  ）
        //  数据全部都回来  才 开始处理   Promise.all 
        const res = await Promise.all([request.get('/area/hot'), request.get('/area/city?level=1')])
        // console.log(res);
        const hotCitys = res[0].body;
        // 将所有城市的数据 先根据名称 进行正序排序
        const allCitys = res[1].body.sort((a, b) => { return a.short < b.short ? -1 : 1 });
        // console.log(allCitys);
        // 5.开始合并成 最终可以渲染到页面的数组 的数据格式  selectList
        const uniList = [];  //合并后的数组
        // 字母列表业务--初始化字母数组
        const letterList = ["#", "热"]
        // 6.添加当前城市
        uniList.push({
            title: "当前定位",
            list: [{ label: cityName }]
        })
        // 7.添加热门城市
        uniList.push({
            title: "热门城市",
            list: hotCitys
        })
        // 8.添加所有城市
        // 首先：要处理的数据 是allCitys数组(后台返回的) 中的数据，遍历
        allCitys.forEach(allCitysItem => {
            // 1.要获取到 "A" 这个字母     获取字符串的首字母： "abc"[0] ==>结果是 a
            const firstLetter = allCitysItem.short[0].toUpperCase()


            // 判断 安庆这个对象是 存在于 uniList 中，用findIndex方法
            //findIndex方法：如果存在返回一个 当前数组找到的第一个元素的索引值，找不到则返回-1
            const index = uniList.findIndex(uniListItem => {
                // 1.要获取到 "A" 这个字母     获取字符串的首字母： "abc"[0] ==>结果是 a
                // const firstLetter = allCitysItem.short[0].toUpperCase()
                //判断
                if (firstLetter === uniListItem.title) {
                    return true;
                } else { return false }
            });

            // 根据index 去判断  "安庆"这个对象 是否存在
            // 如果不存在 则要往uniList 创建添加 { title :“A”, list:[allCitysItem]  } 
            // 如果存在，不需再添加title; 只需把 allCitys这个数组中的 每一项的 label 塞进uniList的 list里面即可 
            if (index === -1) {
                // 不存在
                uniList.push({
                    title: firstLetter,
                    list: [allCitysItem]
                })
                // 不存在的时候 才追加，已经存在就没必要再追加
                letterList.push(firstLetter)
            } else {
                //只需把 allCitys这个数组中的 每一项 塞进 当前对象（uniList中有title属性的对象）的list数组即可
                uniList[index].list.push(allCitysItem)
            }
        });
        // console.log(uniList);
        // 9.最后 合并成的把uniList数组更新到state中的 selectList
        this.setState({
            selectList: uniList,
            letterList
        })
    }

    // 改成使用  react-virtualized渲染 --城市列表的每一项 渲染函数
    // 城市列表的每一项 渲染函数
    rowRenderer = ({
        key, // Unique key within array of rows
        index, // Index of row within collection
        isScrolling, // The List is currently being scrolled
        isVisible, // This row is visible within the List (eg it is not an overscanned row)
        style, // Style object to be applied to row (to position it)
    }) => {
        const { selectList } = this.state;
        const item = selectList[index];
        return (
            <div key={key} style={style}>
                <div className={indexCss.citylist_group_title}>{item.title}</div>
                <div className={indexCss.citylist_group_itemlist}>
                    {
                        item.list.map(v => <div
                            key={v.label}
                            className={indexCss.citylist_group_itemlist_cityitem}
                            // 选中城市，并传递当前选中的值 作为参数
                            onClick={this.selectedCity.bind(this, v.label)}
                        >
                            {v.label}
                        </div>)
                    }
                </div>
            </div>
        );
    }
    // 动态计算 list中每一大行的高度 (当前城市,热门城市 一行)
    rowHeight = ({ index }) => {
        const { selectList } = this.state;
        // 标题和 城市 高都是 40px

        return (selectList[index].list.length + 1) * 40
    }

    // 选中城市的业务
    selectedCity = (currentCity) => {   //接收当前选中的城市
        // 1.修改redux的城市值--调用组件中的方法（前提是要组件中有这个方法 使用mapDispatchToProps）
        this.props.changeCurrentCity(currentCity)   //传参--当前选中的城市
        // 2.返回上一页
        this.props.history.goBack();
    }

    // 切换字母列表中的字母
    changeLetter = (index) => { //传入字母列表的索引值
        // console.log(index);
        this.setState({
            currentIndex: index,
        })
        // console.log(this.listRef);
        //优化 页面滑动，切换右侧字母 业务： 调用list组件的方法 让他 根据一个索引进行 滚动
        this.listRef.scrollToRow(index);
    }
    // 页面滚动 渲染完毕 会触发的回调函数  //页面滑动，切换右侧字母 业务
    scrollRowsRendered = ({ overscanStartIndex, overscanStopIndex, startIndex, stopIndex }) => {
        // console.log(startIndex);    // 滑动时，显示 页面顶部的索引
        // console.log(stopIndex);     // 滑动时，显示 页面底部的索引
        this.setState({
            currentIndex: startIndex
        })
    }

    render() {
        const { selectList, letterList, currentIndex } = this.state;
        return (
            <div>
                {/* 头部导航 */}
                <NavBar
                    mode="light"
                    icon={<Icon type="left" color="#23bb77" />}
                    onLeftClick={() => this.props.history.goBack()}
                    className={indexCss.navbar}
                >城市选择
                </NavBar>
                {/* 城市列表 */}
                <div className={indexCss.citylist_view}>
                    {/* 改成使用  react-virtualized渲染*/}
                    <List
                        ref={ref => this.listRef = ref}     //优化 页面滑动，切换右侧字母 业务
                        rowCount={selectList.length}
                        width={window.outerWidth}
                        height={window.outerHeight - 45}
                        rowHeight={this.rowHeight}
                        rowRenderer={this.rowRenderer}
                        scrollToAlignment="start"         //滑动到哪个位置，列表停留在内容的 上/中middle/下end
                        scrollToIndex={currentIndex}      //滑动到哪个索引，和右边的字母列表联动
                        onRowsRendered={this.scrollRowsRendered}  //页面滑动，切换右侧字母 业务
                    />
                    {/* 字母列表 */}
                    <div className={indexCss.letter_list}>
                        {letterList.map((v, i) => <div
                            // 动态添加active类
                            className={[indexCss.letter_item, i === currentIndex ? indexCss.active : ""].join(" ")}
                            key={v}
                            onClick={() => { this.changeLetter(i) }}>
                            <span>{v}</span>
                        </div>)}
                    </div>
                </div>
            </div>
        )
    }
}

// 1.2 映射对象 将仓库(store)中的数据映射到 当前组件的属性中
const mapStateToProps = (state) => ({
    //语法-自定义属性名: state.仓库管理员名称.state中的属性
    cityName: state.mapReducer.cityName
})

// 1.4把action 操作数据的方法也映射出去
// 选中城市 修改redux的城市值 业务
const mapDispatchToProps = (dispatch) => ({
    // 自定义改变当前城市名的方法
    changeCurrentCity(currentCity) {
        // console.log('派发事件 通知给管理员', currentCity);
        // 派发事件 通知给管理员
        dispatch(changeCityName(currentCity));
    }
})


// 1.3 用 connect方法 将store中的数据通过props的方式传递到 当前的组件
// export default connect(mapStateToProps, mapDispatchToProps)(Index);
export default connect(mapStateToProps, mapDispatchToProps)(Index);